﻿using System;
using MemoryPack;

namespace Hsenl {
    // AI节点与并行节点的唯一区别就在于, AI节点同一时间只允许一个节点处于Running状态, 如果有靠前的节点返回Running状态, 那么他会顶掉后面的那个Running状态的节点, 是状态机的逻辑.
    // 与并行与节点和并行或节点的区别在于, 不会捕捉下面的succ, fail, 最终向上返回的只会是 continue, break 或者 return
    [MemoryPackable]
    public partial class AICompositeNode<TManager> : CompositeNode<TManager, INode<TManager>> where TManager : class, IBehaviorTree {
        [MemoryPackIgnore]
        private INode _currentRunningNode;
        
        protected new void SetNodeStatus(INode node, NodeStatus status) {
            throw new NotImplementedException();
        }

        protected sealed override bool OnNodeEvaluate() {
            return this.children.Count != 0;
        }

        protected sealed override NodeStatus OnNodeTick() {
            var pos = 0;
            CONTINUE:
            if (pos == this.children.Count) {
                // 不出意外情况下, 会向上层返回continue状态
                return NodeStatus.Continue;
            }

            var child = this.children[pos];

            var status = NodeStatus.Continue;
            if (child.EvaluateNode()) {
                status = child.TickNode();
            }

            switch (status) {
                case NodeStatus.Continue:
                case NodeStatus.Success:
                case NodeStatus.Failure:
                    base.SetNodeStatus(child, status);
                    pos++;
                    break;

                // 并行节点是所有节点都受限制的tick. 而AI节点是, 如果有Running节点则跳出
                case NodeStatus.Running:
                    if (this._currentRunningNode != null && this._currentRunningNode != child) {
                        base.SetNodeStatus(this._currentRunningNode, NodeStatus.Failure);
                        this._currentRunningNode = child;
                    }

                    base.SetNodeStatus(child, status);
                    child.Run();
                    return NodeStatus.Running;

                case NodeStatus.Break:
                    if (this._currentRunningNode != null && this._currentRunningNode != child) {
                        base.SetNodeStatus(this._currentRunningNode, NodeStatus.Failure);
                    }

                    base.SetNodeStatus(child, status);
                    // 立即停止当前复合节点, 并向上层返回continue, 这里不返回break, 为的是保证break的影响只在当前复合节点之内
                    return NodeStatus.Continue;

                case NodeStatus.Return:
                    if (this._currentRunningNode != null && this._currentRunningNode != child) {
                        base.SetNodeStatus(this._currentRunningNode, NodeStatus.Failure);
                    }

                    base.SetNodeStatus(child, status);
                    // 立即停止当前复合节点, 且向上层返回return, 让return的影响扩散至整个行为树
                    return NodeStatus.Return;

                default:
                    throw new ArgumentOutOfRangeException();
            }

            goto CONTINUE;
        }
    }
}